package cn.flying.cloud.base.common.utils.lang;

import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.interfaces.RSAPublicKey;
import java.text.ParseException;
import java.util.Arrays;
import java.util.Date;
import java.util.Map;
import java.util.UUID;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.nimbusds.jose.JOSEException;
import com.nimbusds.jose.JWSAlgorithm;
import com.nimbusds.jose.JWSHeader;
import com.nimbusds.jose.JWSVerifier;
import com.nimbusds.jose.crypto.RSASSASigner;
import com.nimbusds.jose.crypto.RSASSAVerifier;
import com.nimbusds.jwt.JWTClaimsSet;
import com.nimbusds.jwt.JWTParser;
import com.nimbusds.jwt.SignedJWT;

/**
 * JWT Token生成器
 *
 * @author: admin
 * @date: 2024年05月17日 10:33
 * @version: 1.0
 */
public class JwtUtil {
    private static final Logger logger = LoggerFactory.getLogger(JwtUtil.class);

    /**
     * 生成JWT令牌
     *
     * @param subject 主体
     * @return
     * @throws NoSuchAlgorithmException
     * @throws JOSEException
     */
    public static String createToken(String subject) throws NoSuchAlgorithmException, JOSEException {
        // 定义JWT的相关声明
        JWTClaimsSet claimsSet = new JWTClaimsSet.Builder()
                .subject(subject) // 主题（用户）
                .issuer(subject) // 签发者
                .expirationTime(new Date(System.currentTimeMillis() + 3600 * 1000)) // 过期时间，例如1小时后
                .issueTime(new Date()) // 签发时间
                .jwtID(UUID.randomUUID().toString()) // JWT ID，用于唯一标识JWT
                .claim("scope", "all") // 自定义声明，如权限范围
                .build();

        // 输出JWT字符串
        return getSignedJwt(claimsSet).serialize();
    }

    /**
     * 生成JWT令牌
     *
     * @param subject 主体
     * @param issuer  发行者
     * @param jwtId   唯一标识
     * @param expire  过期时间（毫秒）
     * @return 令牌字符串
     * @throws JOSEException
     */
    public static String createToken(String subject, String issuer, String jwtId, long expire) throws NoSuchAlgorithmException, JOSEException {
        // 定义JWT的相关声明
        JWTClaimsSet claimsSet = new JWTClaimsSet.Builder()
                .subject(subject) // 主题（用户）
                .issuer(issuer) // 签发者
                .expirationTime(new Date(System.currentTimeMillis() + expire)) // 过期时间
                .issueTime(new Date()) // 签发时间
                .jwtID(jwtId) // JWT ID，用于唯一标识JWT
                .claim("scope", "all") // 自定义声明，如权限范围
                .build();

        // 输出JWT字符串
        return getSignedJwt(claimsSet).serialize();
    }

    /**
     * 解析JWT令牌
     *
     * @param token
     * @return
     */
    public static Map<String, Object> parseToken(String token) {
        try {
            if (token.startsWith("Bearer ")) {
                token = token.replace("Bearer ", "");
            }
            SignedJWT jwt = (SignedJWT) JWTParser.parse(token);
            //{
            //  "sub":"admin",
            //  "scope":"all",
            //  "iss":"admin",
            //  "exp":1740583085,
            //  "iat":1740579485,
            //  "jti":"07f6789f-4fa4-4bc2-8907-badc7331b915"
            //}
            return ((SignedJWT) jwt).getPayload().toJSONObject();
        } catch (Exception e) {
            logger.error("Token解析失败", e);
            return null;
        }
    }

    /**
     * 从令牌中获取主题
     *
     * @param token 令牌
     * @return
     */
    public static String getSubject(String token) {
        try {
            if (token.startsWith("Bearer ")) {
                token = token.replace("Bearer ", "");
            }
            SignedJWT jwt = (SignedJWT) JWTParser.parse(token);
            return jwt.getJWTClaimsSet().getSubject();
        } catch (Exception e) {
            logger.error("解析Token中的主题失败", e);
            return "";
        }
    }

    /**
     * 从token中获取过期时间
     */
    public static Date getExpiredDate(String token) {
        try {
            if (token.startsWith("Bearer ")) {
                token = token.replace("Bearer ", "");
            }
            SignedJWT jwt = (SignedJWT) JWTParser.parse(token);
            return jwt.getJWTClaimsSet().getExpirationTime();
        } catch (Exception e) {
            logger.error("解析Token中的过期时间失败", e);
            return null;
        }
    }

    /**
     * 判断令牌是否过期
     *
     * @param token 令牌
     * @return 是否过期
     */
    public static Boolean isExpired(String token) {
        Date expiration = getExpiredDate(token);
        if (expiration == null) {
            return true;
        }
        return expiration.before(new Date());
    }

    /**
     * 验证JWT令牌
     *
     * @param token 令牌字符串
     * @return 是否有效
     * @throws ParseException 如果解析失败
     * @throws JOSEException  如果发生JOSE异常
     */
    public static boolean validateToken(String token) throws ParseException, JOSEException, NoSuchAlgorithmException {
        SignedJWT signedJwt = SignedJWT.parse(token);

        KeyPair keyPair = getKeyPair();
        JWSVerifier verifier = new RSASSAVerifier((RSAPublicKey) keyPair.getPublic());
        if (!signedJwt.verify(verifier)) {
            return false; // 签名无效
        }

        JWTClaimsSet claimsSet = signedJwt.getJWTClaimsSet();
        Date expirationTime = claimsSet.getExpirationTime();
        return expirationTime == null || !expirationTime.before(new Date()); // 令牌已过期
        // 可以在此处增加更多验证逻辑，比如检查发行者等
    }

    /**
     * 定义签名密钥
     *
     * @return
     * @throws NoSuchAlgorithmException
     */
    private static KeyPair getKeyPair() throws NoSuchAlgorithmException {
        // 定义签名密钥
        KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
        keyGen.initialize(2048);
        return keyGen.generateKeyPair();
    }

    /**
     * 获取签名
     *
     * @param claimsSet
     * @return
     * @throws NoSuchAlgorithmException
     * @throws JOSEException
     */
    private static SignedJWT getSignedJwt(JWTClaimsSet claimsSet) throws NoSuchAlgorithmException, JOSEException {
        // 定义签名密钥
        KeyPair keyPair = getKeyPair();
        RSASSASigner signer = new RSASSASigner(keyPair.getPrivate());
        // 构建SignedJWT
        JWSHeader jwsHeader = new JWSHeader.Builder(JWSAlgorithm.RS256).keyID(Arrays.toString(keyPair.getPublic().getEncoded())).build();
        SignedJWT signedJwt = new SignedJWT(jwsHeader, claimsSet);
        // 签名JWT
        signedJwt.sign(signer);

        return signedJwt;
    }

    public static void main(String[] args) throws ParseException, NoSuchAlgorithmException, JOSEException {
        String token = "eyJraWQiOiJbNDgsIC0xMjYsIDEsIDM0LCA0OCwgMTMsIDYsIDksIDQyLCAtMTIyLCA3MiwgLTEyMiwgLTksIDEzLCAxLCAxLCAxLCA1LCAwLCAzLCAtMTI2LCAxLCAxNSwgMCwgNDgsIC0xMjYsIDEsIDEwLCAyLCAtMTI2LCAxLCAxLCAwLCAtODQsIC01MywgLTQ1LCAtOCwgLTQxLCAtNDEsIDcwLCAtOSwgLTU4LCAtNjcsIC0xMywgNjQsIC0xMTIsIC0zOSwgMTIxLCAtMzAsIDc4LCAtNTMsIC05NiwgNjYsIDEyMSwgLTI0LCAtNSwgODMsIC0xMDYsIC00NywgNjAsIDc5LCAzOCwgNzgsIC04NCwgLTEwMiwgMCwgMjEsIC03MSwgMTEwLCAtMjUsIC0zMCwgLTUwLCA0NCwgLTEyNiwgMjIsIC0xMTQsIDM0LCAtMjQsIC0yNywgLTUsIDU2LCAtMzgsIC0xMDYsIC04OSwgMTcsIDEyNCwgLTY3LCAtMTAzLCAxMjUsIDQxLCAtNjIsIC0xMTQsIC0xNywgMTE1LCAtNjMsIC05MCwgLTQxLCAtMTA0LCAtNzQsIC05NywgMzIsIC0xMTAsIC0xMjMsIC02MSwgMTEwLCA2NCwgLTQwLCAtODAsIDk3LCAxMDYsIDk3LCAtMTUsIDk2LCAtNzksIDUxLCA0MCwgLTI5LCAtOSwgNDYsIDExMSwgMTA1LCAtNzQsIC05MSwgLTcsIC0xMTUsIDcxLCA5OCwgOCwgMTA5LCAxMTYsIDc0LCAzNiwgNTEsIDEzLCAzNCwgLTU1LCAtMjQsIC01NCwgLTQ1LCAtMTIxLCAxMjUsIC03OCwgOTAsIDQsIC01MCwgOSwgNDksIDMwLCAtMTE1LCA4NiwgLTc2LCAxNiwgLTEyMCwgLTUsIC04NSwgLTQ4LCAxNSwgLTEwOCwgMTE0LCAzMiwgLTU1LCAxMywgMTA5LCA3NCwgNzIsIC01NywgNTUsIDEyMywgLTM3LCA5MCwgMTA4LCAtNzEsIDQzLCA1MywgOTcsIDM3LCAxMywgNzMsIDMwLCAtNTIsIC00MSwgMTEwLCAxMTcsIDQ2LCAxMTEsIC0zMywgOSwgLTExNCwgMTA2LCAtMTAsIDM4LCA1NywgLTUsIDIyLCAxMDIsIDExOCwgLTI4LCAxMDcsIC0xMjQsIC02NiwgODAsIDc0LCAzMSwgLTEwNiwgNDgsIDQ4LCAxMDYsIDQsIC0zNSwgNywgLTYyLCAtMTExLCAxMTYsIC04MywgLTEyNCwgLTg0LCAxMDQsIC0xMjYsIDM3LCAtMTA1LCAtMTE4LCA2MSwgMzQsIDczLCAxMDgsIC0yNSwgLTI4LCAtMTA0LCAxMiwgLTM5LCAyNiwgLTU3LCAtMzIsIDM5LCAtNTgsIDM1LCAtMTAyLCAzNCwgLTEyMCwgLTEwMCwgMTYsIC0zOSwgMTE4LCAtMTE0LCAtNCwgLTMxLCAtODksIC0yNiwgLTMwLCAtODUsIDgyLCAtMjMsIC01NywgLTE1LCA3MSwgMTA3LCAtMTAxLCA3MywgLTM2LCAtNjAsIC05MCwgMywgLTU1LCAtMTA5LCAtNzQsIDU4LCA5MCwgLTE1LCA5MiwgOTgsIDU1LCAxMjcsIC04LCA4MSwgLTk5LCAxNiwgODgsIDg0LCAtNTksIC0xNSwgLTkyLCAzMSwgLTcsIC05MSwgLTE1LCA4MywgODQsIC0xMjUsIC0zNywgMiwgMywgMSwgMCwgMV0iLCJhbGciOiJSUzI1NiJ9.eyJzdWIiOiJhZG1pbiIsInNjb3BlIjoiYWxsIiwiaXNzIjoiYWRtaW4iLCJleHAiOjE3NDA1ODMwODUsImlhdCI6MTc0MDU3OTQ4NSwianRpIjoiMDdmNjc4OWYtNGZhNC00YmMyLTg5MDctYmFkYzczMzFiOTE1In0.Q5g1DwQo7KrPXq_YSO9IhA5huJKRstLyBmWQNz080ApNu2nJrrDmb1Z9PiPOHuCpXbZVW-nSjIzEaak8dJauoat4EybFeK1Q_IIAaNk6nhF3lmapJhQf3T5fKjCOmGZcVoWBrstN1GUmAj4fNokUGlpua_4HzlreIbnG8nx7_M9ISCaYGspG4sGN7mgC0K-la9DMhTugqzYXzNvbSdrkMQNGsFSjkzG_NdoDb_aTU7IXtActoS3p0yIS4_pSjdv4VpyXttLPI7VEx6lCkriWH_Yl8AoP_gumEOJiJaQGThsSuqOxDYCtFiv2lXIcAb7QYFJt3bl5Z2AKXVWHqaKmkg";
        System.out.println(parseToken(token));
    }
}